<template>
    <div class="game-container">
        <div
            class="mine-sweeper-container"
            @contextmenu.prevent
        >
            <div
                v-for="i in height"
                :key="i"
                class="mine-sweeper-row"
            >
                <div
                    v-for="j in width"
                    :key="j"
                    class="mine-sweeper-item"
                    :class="{ 'is-open': openStatus[(i - 1) * width + j - 1] }"
                    @click.left="handleLeftClick(i - 1, j - 1)"
                    @click.right="handleRightClick(i - 1, j - 1)"
                >
                    <span
                        v-if="markStatus[(i - 1) * width + (j - 1)] === 1"
                        class="iconfont"
                    >&#xe778;</span>
                    <span
                        v-else-if="markStatus[(i - 1) * width + (j - 1)] === 2"
                        class="iconfont"
                    >&#xe720;</span>
                    <template v-else-if="openStatus[(i - 1) * width + (j - 1)]">
                        <img
                            v-if="mines[(i - 1) * width + (j - 1)]"
                            :src="require('../assets/img/boom.png')"
                            class="boom"
                        >
                        <span v-else-if="neighbourMineCount[(i - 1) * width + (j - 1)] > 0">
                            {{ neighbourMineCount[(i - 1) * width + (j - 1)] }}
                        </span>
                    </template>
                </div>
            </div>
        </div>
        <div class="panel-container">
            <div class="panel-data-container">
                <span
                    class="iconfont"
                    style="font-size: 60px"
                >&#xe778;</span>
                <div>{{ selectedMineCount }} / {{ mineCount }}</div>
            </div>
            <div>
                <button
                    class="mine-sweeper-button"
                    @click="reStart"
                >
                    重开一局
                </button>

                <button
                    class="mine-sweeper-button"
                    style="margin-top: 15px"
                    @click="$emit('selectDifficulty')"
                >
                    改变难度
                </button>
            </div>
        </div>

        <div
            v-if="!!showWord"
            class="word"
        >
            祝您新的一年：{{ showWord }}
        </div>
    </div>
</template>

<script>
import {
    word,
} from '../assets/js/constant';

function shuffle (mines, start) {
    for (let i = start; i < mines.length; i++) {
        const randomIndex = Math.floor(Math.random() * (i + 1));
        const tmp = mines[randomIndex];
        mines[randomIndex] = mines[i];
        mines[i] = tmp;
    }
}

export default {
    props: {
        play: {
            type: Boolean,
            required: true,
        },
        width: {
            type: Number,
            required: true,
        },
        height: {
            type: Number,
            required: true,
        },
        mineCount: {
            type: Number,
            required: true,
        },
    },
    data () {
        return {
            // 是否游戏结束
            isEnd: false,
            // 记录爆竹的位置，1：代表该位置有爆竹，0：没有
            mines: [],
            // 打开的状态
            openStatus: [],
            // 标记状态
            markStatus: [],
            // 被标记的爆竹数量
            selectedMineCount: 0,
            // 显示的祝福语
            showWord: '',
        };
    },
    computed: {
        // 计算周围爆竹数量
        neighbourMineCount () {
            const result = new Array(this.width * this.height).fill(0);
            for (let i = 0; i < result.length; i++) {
                if (!this.mines[i]) {
                    continue;
                }
                const y = i % this.width;
                const x = (i - y) / this.width;
                for (let j = -1; j < 2; j++) {
                    const newX = x + j;
                    if (newX < 0 || newX === this.height) {
                        continue;
                    }
                    for (let k = -1; k < 2; k++) {
                        const newY = y + k;
                        if (newY < 0 || newY === this.width) {
                            continue;
                        }
                        result[newX * this.width + newY]++;
                    }
                }
            }
            return result;
        },
    },
    watch: {
        play () {
            if (!this.play) {
                return;
            }
            this.init(this.width, this.height, this.mineCount);
        },
        selectedMineCount () {
            if (this.selectedMineCount === this.mineCount) {
                const match = this.mines.every((isMine, index) => {
                    if (
                        (isMine && this.markStatus[index] === 1) ||
            (!isMine && this.markStatus[index] !== 1)
                    ) {
                        return true;
                    }
                    return false;
                });
                if (match) {
                    this.$nextTick(() => {
                        this.playFire();
                    });
                    this.isEnd = true;
                }
            }
        },
    },
    methods: {
        reStart () {
            this.init(this.width, this.height, this.mineCount);
        },
        init (width, height, mineCount) {
            this.isEnd = false;
            const total = width * height;
            const mines = new Array(total).fill(0);
            for (let i = 0; i < mineCount; i++) {
                mines[i] = 1;
            }
            shuffle(mines, mineCount);
            this.mines = mines;
            this.openStatus = new Array(total).fill(0);
            this.markStatus = new Array(total).fill(0);
            this.selectedMineCount = 0;
        },
        handleLeftClick (x, y) {
            if (this.isEnd) {
                return;
            }
            const index = x * this.width + y;
            if (this.openStatus[index] === 1 || this.markStatus[index] === 1) {
                return;
            }

            if (this.mines[index]) {
                this.openStatus.splice(index, 1, 1);
                this.isEnd = true;
                this.$nextTick(() => {
                    alert('哎呀，一不小心提前点燃了，再接再厉！');
                });

                return;
            }
            if (this.neighbourMineCount[index] > 0) {
                this.openStatus.splice(index, 1, 1);
                return;
            }
            this.floodfill(x, y);
        },
        floodfill (x, y) {
            if (x < 0 || y < 0 || x === this.height || y === this.width) {
                return;
            }
            const index = x * this.width + y;
            if (this.openStatus[index] === 1) {
                return;
            }
            this.openStatus.splice(index, 1, 1);
            if (this.neighbourMineCount[index] > 0) {
                return;
            }
            for (let i = -1; i < 2; i++) {
                for (let j = -1; j < 2; j++) {
                    this.floodfill(x + i, y + j);
                }
            }
        },
        handleRightClick (x, y) {
            if (this.isEnd) {
                return;
            }
            const index = x * this.width + y;
            if (this.openStatus[index] === 1) {
                return;
            }
            this.markStatus.splice(index, 1, (this.markStatus[index] + 1) % 3);
            if (this.markStatus[index] === 1) {
                this.selectedMineCount++;
            } else if (this.markStatus[index] === 2) {
                this.selectedMineCount--;
            }
        },
        playFire () {
            const index = Math.floor(Math.random() * word.length);
            this.showWord = word[index];

            // eslint-disable-next-line
            $("#app").fireworks({
                sound: true, // 声音效果
                opacity: 0.5,
                width: '100%',
                height: '100%',
            });
        },
    },
};
</script>

<style scoped>
.game-container {
  display: flex;
  justify-content: space-between;
  padding: 0 15px;
}

.mine-sweeper-container {
  overflow: hidden;
  width: fit-content;
  margin: 0 auto;
  background-color: rgb(163, 50, 50);
}

.mine-sweeper-row {
  display: flex;
}

.mine-sweeper-item {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  margin: 2px;
  line-height: 50px;
  font-size: 34px;
  text-align: center;
  background: url("../assets/img/item.png");
  cursor: pointer;
}

.mine-sweeper-item.is-open {
  background: url("../assets/img/item-open.png");
  color: white;
}

.panel-container {
  width: 180px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.panel-data-container {
  padding-top: 15px;
  text-align: center;
}

.iconfont {
  color: white;
}

.boom {
  width: 40px;
}

.word {
    width: 100%;
    position: fixed;
    top: 50px;
    left: 100%;
    font-size: 50px;
    color: gold;
    text-align: center;
    background-image: -webkit-linear-gradient(left,gold,#ffca99 10%,#cc00ff 20%,#CC00CC 30%, #CCCCFF 40%, #FFFFCC 50%,#CCCCFF 60%,#CC00CC 70%,#CC00FF 80%, #99CCFF 90%,gold 100%);
    -webkit-text-fill-color: transparent;/* 字体设置成透明色 */
    background-clip: text;/* 裁剪背景，使文字作为裁剪区域向外裁剪 */
    background-size: 200% 100%;
    animation: masked-animation 4s linear infinite;
    z-index: 999999;
}

@keyframes masked-animation {
    0% {
        background-position: 0  0;
    }
    100% {
        background-position: -100%  0;
    }
}
</style>
